package com.idroc.cdfs.service.meta;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Properties;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import net.sf.lipermi.exception.LipeRMIException;
import net.sf.lipermi.handler.CallHandler;
import net.sf.lipermi.net.Client;

import com.idroc.cdfs.node.impl.StorageNode;
import com.idroc.cdfs.node.impl.StorageNode.BerkeleyCollection;
import com.idroc.cdfs.service.meta.RegistryManager.RegistryItem.ItemState;
import com.sleepycat.collections.StoredMap;

/**
 * 
 * @author 詹都林(zhandl@tianya.cn) <br>
 * @date Aug 10, 2009 10:26:48 PM <br>
 * @version 1.0.0
 * @descript: 类功能简称<br>
 *            <p>
 *            备注:<br>
 *            </p>
 */
public final class RegistryManager {
	
	private static final Logger log = LoggerFactory.getLogger(RegistryManager.class);
	
	public static final String REGISTRY_CONFIG_CATALOG = "registry_config_catalog";
	
	public static final String CONFIG_MAP = "config_map";
	
	public static final String ROOT_META_NODE = "root_meta_node";
	public static final String ROOT_META_NODE_HOST = "root_meta_node_host";
	public static final String ROOT_META_NODE_PORT = "root_meta_node_port";
	
	public static final String META_NODE_HOST = "meta_node_host";
	public static final String META_NODE_PORT = "meta_node_port";
	
	/**
	 * 节点注册信息载体类
	 * @author 詹都林(zhandl@tianya.cn) <br>
	 * @date Aug 10, 2009 10:45:24 PM <br>
	 * @version 1.0.0
	 * @descript: 类功能简称<br>
	 *            <p>
	 *            备注:<br>
	 *            </p>
	 */
	public static class RegistryItem implements Serializable {
		
		public static enum ItemState {CONNECT, REGISTRY, OPEN, CLOSE, UNREGISTRY, DISCONNECT, SYNC};

		private  String nodeHost = null;
		private  int nodePort = -1;
		private int nodeNo = -1;
		private  ItemState nodeState = ItemState.DISCONNECT;
		
		String getNodeHost() {
			return nodeHost;
		}
		void setNodeHost(String nodeHost) {
			this.nodeHost = nodeHost;
		}
		int getNodePort() {
			return nodePort;
		}
		void setNodePort(int nodePort) {
			this.nodePort = nodePort;
		}
		
		ItemState getNodeState() {
			return nodeState;
		}
		
		void setNodeState(ItemState nodeState) {
			this.nodeState = nodeState;
		}
		public int getNodeNo() {
			return nodeNo;
		}
		public void setNodeNo(int nodeNo) {
			this.nodeNo = nodeNo;
		}
		
	}
	
	private StorageNode storageNode = null;
	private int storageNodeNo = -1;
	private boolean isRootMetaNode = false;
	
	private BerkeleyCollection coll = null;
	private StoredMap store = null;
	private Properties props = null;
	private CallHandler callHandler = null;
	
	private String currentMetaNodeHost = null;
	private int currentMetaNodePort = -1;
	
	private RegistryItem rootMetaItem = null;
	
	public void setStorageNodeNo(int no) {
		storageNodeNo = no;
	}
	
	public void setStorageNode(StorageNode sn) {
		storageNode = sn;
	}

	public void setRootMetaNode(boolean flag) {
		isRootMetaNode = flag;
	}
	
	/**
	 * 初始化
	 * @param p
	 */
	public void initialized(Properties p) {
		
		props = p;		
		
		currentMetaNodeHost = props.getProperty(META_NODE_HOST);
		currentMetaNodePort = Integer.parseInt(props.getProperty(META_NODE_PORT));
		
		coll = storageNode.getBerkeleyCollection(REGISTRY_CONFIG_CATALOG, String.class, HashMap.class);
		store = coll.open();
		
		callHandler = new CallHandler();
	}
	
	/**
	 * 启动注册管理器
	 */
	public void start() {

		try {
			callHandler.registerGlobal(IMetaManageService.class, MetaManageServiceImpl.class);
			
			boolean startup = startupFromLocalBase();
			if (!startup && isRootMetaNode) {		
				buildRootMetaNode();
			} else {
				connectToMetaNodeNetwork();
			}
		} catch (Exception lex) { 
			String errorMsg = "启动注册管理器异常";
			log.error(errorMsg, lex);
			throw new RuntimeException(errorMsg, lex);
		}
	}
	
	/**
	 * 停止注册管理器
	 */
	public void stop() {
		
		if (null != coll) {
			coll.close();
		}
	}
	
	/**
	 * 注册一个元数据节点
	 * @param no -- 节点编号
	 * @param item -- 节点信息
	 * @return -- true,注册成功 
	 */
	public boolean registry(Integer no, RegistryItem item) {
		
		try {
			HashMap config = (HashMap) store.get(CONFIG_MAP);
			config.put(no, item);
			store.put(CONFIG_MAP, config);
		} catch (Exception ex) {
			ex.printStackTrace();
			return false;
		}
		return true;
	}
	
	/**
	 * 从本地保存的meta库中获取元数据根结点信息
	 * @return
	 */
	private boolean startupFromLocalBase() {
		
		try {
			HashMap metaItems = (HashMap) store.get(ROOT_META_NODE);
			if (null == metaItems) {
				metaItems = new HashMap();
			}
			rootMetaItem = (RegistryItem) metaItems.get(ROOT_META_NODE);
			if (null != rootMetaItem) {
				// 获取最新的元数据跟
				rootMetaItem = getRootMetaNode(rootMetaItem);
				if (null != rootMetaItem) {
					
					// 保存最新的元数据节点的根
					metaItems.put(ROOT_META_NODE, rootMetaItem);
					store.put(ROOT_META_NODE, metaItems); 
					
					// 获取最新的已注册地元数据节点集合
					HashMap rn = getRegisteredMetaNode(rootMetaItem);
					if (null != rn) {
						store.put(CONFIG_MAP, rn);
						return true;
					} else {
						String errorMsg = "无法获取最新的已注册地元数据节点集合"; 
						throw new RuntimeException(errorMsg);
					}
				} else {
					
					String errorMsg = "无法获取最新的元数据节点根"; 
					throw new RuntimeException(errorMsg);
				}
			} else {

				HashMap config = (HashMap) store.get(CONFIG_MAP);
				if (null != config) {
					for (Object k : config.keySet()) {
						try {
							RegistryItem ri = (RegistryItem) config.get(k);
							rootMetaItem = getRootMetaNode(ri);
							if (null != rootMetaItem) {
								
								// 保存最新的元数据节点的根
								metaItems.put(ROOT_META_NODE, rootMetaItem);
								store.put(ROOT_META_NODE, metaItems);
								
								// 获取最新的已注册地元数据节点集合
								HashMap rn = getRegisteredMetaNode(rootMetaItem);
								if (null != rn) {
									store.put(CONFIG_MAP, rn);
									return true;
								}  
							} 
						} catch (Exception ex) { /* swallow exception */ }
					}
				}  
			}
			
		} catch (Exception ex) {
			log.error("从本地保存的meta库中获取元数据根结点信息失败.", ex);
		}
		return false;
	}
	
	/**
	 * 本地建立元数据节点的根
	 */
	private void buildRootMetaNode() {
		
		RegistryItem ri = new RegistryItem();
		ri.setNodeHost(currentMetaNodeHost);
		ri.setNodePort(currentMetaNodePort);
		ri.setNodeState(ItemState.OPEN); 
		HashMap rootItem = new HashMap();
		rootItem.put(ROOT_META_NODE, ri);
		store.put(ROOT_META_NODE, rootItem);
		rootMetaItem = ri;
		registry(Integer.valueOf(storageNodeNo), rootMetaItem);		
	}
	
	/**
	 * 连接元数据节点网络
	 */
	private void connectToMetaNodeNetwork() {
		
		try {
			CallHandler callHandler = new CallHandler(); 
			
			String rootHost = props.getProperty(ROOT_META_NODE_HOST);
			String rootPort = props.getProperty(ROOT_META_NODE_PORT);
			Client client = new Client(rootHost, Integer.parseInt(rootPort), callHandler);
			IMetaManageService ms = (IMetaManageService) client.getGlobal(IMetaManageService.class);
			RegistryItem rmi = ms.getRootMetaNode(); 
			if (null != rmi) {
				
				// 保存最新的元数据节点的根
				HashMap metaItems = new HashMap();
				metaItems.put(ROOT_META_NODE, rmi);
				store.put(ROOT_META_NODE, metaItems);
				rootMetaItem = rmi;
				
				// 获取最新的已注册地元数据节点集合
				HashMap rn = getRegisteredMetaNode(rootMetaItem);
				if (null != rn) {
					store.put(CONFIG_MAP, rn); 
				} else {
					String errorMsg = "无法获取最新的已注册地元数据节点集合"; 
					throw new RuntimeException(errorMsg);
				}
			} else {
				
				String errorMsg = "无法获取最新的元数据节点根"; 
				throw new RuntimeException(errorMsg);
			} 
		} catch (Exception ex) {
			String errorMsg = "连接元数据节点网络失败";
			log.error(errorMsg, ex);
			throw new RuntimeException(errorMsg, ex);
		}
	}
	
	/**
	 * 通过一个注册节点获取元数据节点根
	 * @param src -- 注册节点
	 * @return 元数据节点根
	 */
	private RegistryItem getRootMetaNode(RegistryItem src) {
		
		try {
			CallHandler callHandler = new CallHandler(); 
			Client client = new Client(currentMetaNodeHost, currentMetaNodePort, callHandler);
			IMetaManageService ms = (IMetaManageService) client.getGlobal(IMetaManageService.class);
			RegistryItem rmi = ms.getRootMetaNode();
			return rmi;
		} catch (Exception ex) {
			String errorMsg = "通过一个注册节点获取元数据节点根信息失败";
			log.error(errorMsg, ex);
			throw new RuntimeException(errorMsg, ex);
		}
	}
	
	/**
	 * 通过一个注册节点获取已注册地元数据节点集合
	 * @param src -- 注册节点 
	 * @return -- 已注册地元数据节点集合
	 */
	private HashMap getRegisteredMetaNode(RegistryItem src) {

		try {
			CallHandler callHandler = new CallHandler(); 
			Client client = new Client(currentMetaNodeHost, currentMetaNodePort, callHandler);
			IMetaManageService ms = (IMetaManageService) client.getGlobal(IMetaManageService.class);
			HashMap mn = ms.getRegisteredMetaNode();
			return mn;
		} catch (Exception ex) {
			String errorMsg = "通过一个注册节点获取已注册地元数据节点集合失败";
			log.error(errorMsg, ex);
			throw new RuntimeException(errorMsg, ex);
		}
	}

	public RegistryItem getRootMetaItem() {
		return rootMetaItem;
	}
}
